package com.zdp.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zdp.commons.util.Constants;
import com.zdp.commons.util.JwtUtil;
import com.zdp.commons.util.TotpUtil;
import com.zdp.domain.Auth;
import com.zdp.domain.Role;
import com.zdp.domain.User;
import com.zdp.domain.UserRole;
import com.zdp.mapper.RoleMapper;
import com.zdp.mapper.UserRoleMapper;
import com.zdp.mapper.UsersMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * @author sesshomaru
 * @date 2021/7/7
 */
@RequiredArgsConstructor
@Service
public class UserService {

    private final UsersMapper usersMapper;
    private final PasswordEncoder passwordEncoder;
    private final RoleMapper roleMapper;
    private final UserRoleMapper userRoleMapper;
    private final JwtUtil jwtUtil;
    private final TotpUtil totpUtil;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public User register(User user) {
        // 赋默认的权限
        QueryWrapper<Role> roleQueryWrapper = new QueryWrapper<>();
        String authority = Constants.ROLE_ROOT;
        roleQueryWrapper.eq("role_name", authority);
        // 校验是否存在权限
        Role role = roleMapper.selectOne(roleQueryWrapper);
        if (!Optional.ofNullable(role).isPresent()) {
            role = new Role();
            role.setAuthority(authority);
            // 不存在则创建新的权限
            roleMapper.insert(role);
        }
        // 添加用户
        user.withMfaKey(totpUtil.encodeKeyToString());
        user.withPassword(passwordEncoder.encode(user.getPassword()));
        usersMapper.insert(user);
        // 绑定关系
        userRoleMapper.insert(
                UserRole.builder()
                        .userId(user.getId())
                        .roleId(role.getId())
                        .build()
        );
        user.setAuthorities(Set.of(role));
        return user;
    }

    public User findOptionalByUsernameAndPassword(String username, String password) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = usersMapper.selectOne(queryWrapper);
        if (passwordEncoder.matches(password, user.getPassword())) {
            return user;
        }
        return null;
    }

    public Auth login(String username, String password) throws AuthenticationException {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = usersMapper.selectOne(queryWrapper);
        if (!Optional.ofNullable(user).isPresent()) throw new BadCredentialsException("没有找到用户名或密码参数");
        String pwd = user.getPassword();
        // 添加权限
        Set<Role> roles = new HashSet<>();
        // 查询当前用户具备的权限
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id", user.getId());
        List<UserRole> userRoles = userRoleMapper.selectList(userRoleQueryWrapper);
        for (UserRole userRole : userRoles) {
            Role role = roleMapper.selectById(userRole.getRoleId());
            roles.add(role);
        }
        user.setAuthorities(roles);
        // 比较用户输入的密码和数据库中加密后的密码是否一致
        Auth auth = new Auth();
        if (passwordEncoder.matches(password, pwd)) {
            String accessToken = jwtUtil.createAccessToken(user);
            auth.setAccessToken(accessToken);
            String refreshToken = jwtUtil.createRefreshToken(user);
            auth.setRefreshToken(refreshToken);
        } else {
            throw new BadCredentialsException("密码有误");
        }
        return auth;
    }

    public boolean isUserNameExisted(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        return usersMapper.selectCount(queryWrapper) > 0;
    }

    public boolean isEmailExisted(String email) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        return usersMapper.selectCount(queryWrapper) > 0;
    }

    public boolean isMobileExisted(String mobile) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobile);
        return usersMapper.selectCount(queryWrapper) > 0;
    }

    // 更新升级密码
    public void upgradePasswordEncodingIfNeeded(User user, String rawPassword) {
        if (passwordEncoder.upgradeEncoding(user.getPassword())) {
            user.withPassword(passwordEncoder.encode(rawPassword));
            usersMapper.updateById(user);
        }
    }

    public Optional<String> createTotp(String key) {
        return totpUtil.createTotp(key);
    }


    public boolean isValidUser(Authentication authentication, String username) {
        return authentication.getName().equalsIgnoreCase(username);
    }


}
